package com.ruoyi.doorcontrol.service;


import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.StringUtils;

import com.ruoyi.doorcontrol.domain.ThDoorControl;
import com.ruoyi.doorcontrol.domain.ThDoorcontrolUser;
import com.ruoyi.doorcontrol.domain.ThFaceRecords;
import com.ruoyi.doorcontrol.sdk.HCNetSDK;
import com.ruoyi.doorcontrol.service.impl.ThDoorControlServiceImpl;
import com.ruoyi.system.service.ISysDictDataService;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import sun.misc.BASE64Encoder;

import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static com.ruoyi.common.constant.ControlStatus.BUFANG;
import static com.ruoyi.common.constant.ControlStatus.DENGLU;

/**
 * @Author: meng
 * @Date: 2021-05-31 16:07
 */
@Slf4j
@Service
public class HKEventService {
    static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
    final HCNetSDK.FMSGCallBack_V31 callback = new HKEventCallback();
    //key: loginHandler  value: subscribeHandler
    public static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
    private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private ISysDictDataService sysDictDataService;
    @Autowired
    private IThDoorControlService thDoorControlService;

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IThDoorcontrolUserService thDoorcontrolUserService;
    @Autowired
    private IThFaceRecordsService thFaceRecordsService;
    @Autowired
    private HkUserService hkUserService;




    public AjaxResult startSubscribe(Long id) {
        AjaxResult ajaxResult = new AjaxResult();
        ThDoorControl control = thDoorControlService.selectThDoorControlById(id);
        Integer loginHandler = ThDoorControlServiceImpl.loginHandleMap.get(control.getIpadress());
        String msg = "success";
        boolean b = hCNetSDK.NET_DVR_SetDVRMessageCallBack_V31(callback, null);
        if (!b) {
            log.error("订阅失败");
            ajaxResult.put("code",500);
            ajaxResult.put("msg","订阅失败");
        }
        HCNetSDK.NET_DVR_SETUPALARM_PARAM m_strAlarmInfo = new HCNetSDK.NET_DVR_SETUPALARM_PARAM();
        m_strAlarmInfo.dwSize = m_strAlarmInfo.size();
        m_strAlarmInfo.byLevel = 1;
        m_strAlarmInfo.byAlarmInfoType = 1;
        // m_strAlarmInfo.byDeployType = 0;// 客户端布防
        m_strAlarmInfo.byDeployType = 1;// 服务端布防
        m_strAlarmInfo.write();
        int subscribeHandler = hCNetSDK.NET_DVR_SetupAlarmChan_V41(loginHandler, m_strAlarmInfo);
        if (subscribeHandler == -1) {
            int errorCode = hCNetSDK.NET_DVR_GetLastError();
            msg = hCNetSDK.NET_DVR_GetErrorMsg(new IntByReference(errorCode));
            log.error("布防失败");
            ajaxResult.put("code",500);
            ajaxResult.put("msg","布防失败");
        } else {
            map.put(loginHandler, subscribeHandler);
            ajaxResult.put("code",200);
            ajaxResult.put("msg","布防成功");
            control.setStatus(BUFANG);
            thDoorControlService.updateThDoorControl(control);
        }
        return ajaxResult;
    }

    public AjaxResult stopSubscribe(Long id) {
        AjaxResult ajaxResult = new AjaxResult();
        ThDoorControl control = thDoorControlService.selectThDoorControlById(id);
        Integer subscribeHandler = ThDoorControlServiceImpl.loginHandleMap.get(control.getIpadress());
        if (subscribeHandler == null) {
            log.error("stopSubscribe null");
            ajaxResult.put("code",500);
            ajaxResult.put("msg","当前门禁未登录！");
            return ajaxResult;
        }
        Integer integer = map.get(subscribeHandler);
        if(null == integer){
            throw new CustomException("当前门禁未布防！");
        }
        boolean b = hCNetSDK.NET_DVR_CloseAlarmChan_V30(integer);
        //防止数据紊乱（重复登陆等）导致两个map内容不一致，采用循环删除
        for (var loginHandler : map.keySet()) {
            if (subscribeHandler.intValue() == map.get(loginHandler)) {
                map.remove(loginHandler);
            }
        }
        if (!b) {
            log.error("撤防失败");
            ajaxResult.put("code",500);
            ajaxResult.put("msg","撤防失败");
            return ajaxResult;
        }
        ajaxResult.put("code",200);
        ajaxResult.put("msg","撤防成功");
        control.setStatus(DENGLU);
        thDoorControlService.updateThDoorControl(control);

        return ajaxResult;

    }

    public AjaxResult remoteControl(String id) {
        ThDoorControl control = thDoorControlService.selectThDoorControlById(Long.parseLong(id));
        Integer loginHandler = ThDoorControlServiceImpl.loginHandleMap.get(control.getIpadress());
        boolean b_gate = hCNetSDK.NET_DVR_ControlGateway(loginHandler,1,1);
        if (b_gate==false)
        {
            System.out.println("远程控门失败,err="+ hCNetSDK.NET_DVR_GetLastError());
            return AjaxResult.error("远程开门失败！");
        }
        return AjaxResult.success();

    }

    public AjaxResult remoteGate() {
        redisTemplate.opsForValue().set("openGate",1,30, TimeUnit.SECONDS);
        return AjaxResult.success();
    }


    /**
     * 2021-06-09
     */
    class HKEventCallback implements HCNetSDK.FMSGCallBack_V31 {

        @Override
        public boolean invoke(int lCommand, HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser) {
            int loginHandler = pAlarmer.lUserID;
            Integer subscribeHandler = map.get(loginHandler);
            if (subscribeHandler == null) {
                log.error("上报句柄不存在");
            }
            // lCommand是传的报警类型
            switch (lCommand) {
                case HCNetSDK.COMM_ALARM_ACS: // 门禁主机报警信息
                    try {
                        processAlarmEvent(pAlarmer, pAlarmInfo);
                    } catch (Exception e) {
                        log.error("门禁事件异常 error:{}", ExceptionUtils.getStackTrace(e));
                    }
                    break;
                default:
                    break;
            }
            return true;
        }
    }

    private void processAlarmEvent(HCNetSDK.NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo) throws Exception {
        String[] sIP = new String[2];
        sIP = new String(pAlarmer.sDeviceIP).split("\0", 2);
        //报警设备ip
        String ip = sIP[0];
        String eventTime = null;
        String employeeId = null;
        String cardNo = null;
        Byte cardType = null;
        List<JSONObject> userInfo = null;

         HCNetSDK.NET_DVR_ACS_ALARM_INFO strACSInfo = new HCNetSDK.NET_DVR_ACS_ALARM_INFO();
        strACSInfo.write();
        Pointer pACSInfo = strACSInfo.getPointer();
        pACSInfo.write(0, pAlarmInfo.getByteArray(0, strACSInfo.size()), 0, strACSInfo.size());
        strACSInfo.read();
        //主类型 5 事件上报
        if (strACSInfo.dwMajor != 5) {
            return;
        }
        cardNo = new String(strACSInfo.struAcsEventInfo.byCardNo).trim();
        cardType = strACSInfo.struAcsEventInfo.byCardType;
        byte timeType = strACSInfo.byTimeType;
        HCNetSDK.NET_DVR_TIME struTime = strACSInfo.struTime;
        LocalDateTime uplaodTime = LocalDateTime.of(struTime.dwYear, struTime.dwMonth, struTime.dwDay, struTime.dwHour, struTime.dwMinute, struTime.dwSecond);


        //以人为中心设备
        if (strACSInfo.byAcsEventInfoExtend == 1) {var test = new HCNetSDK.NET_DVR_ACS_EVENT_INFO_EXTEND();
            test.write();
            var pAcsEventInfoExtend = test.getPointer();
            pAcsEventInfoExtend.write(0, strACSInfo.pAcsEventInfoExtend.getByteArray(0, test.size()), 0, test.size());
            test.read();
            employeeId = new String(test.byEmployeeNo).trim();

            Integer integer = ThDoorControlServiceImpl.loginHandleMap.get(ip);
            //userInfo = UserControl.searchUserInfo(integer, employeeId);
        }

        if (timeType == 0) {
            eventTime = dtf.format(uplaodTime);
        } else if (timeType == 1) {
            var zonedDateTime = uplaodTime.atZone(ZoneId.from(ZoneOffset.UTC)).withZoneSameInstant(ZoneId.systemDefault());
            eventTime = dtf.format(zonedDateTime);
        } else {
            log.error("上报时间不正确");
        }


        // 刷卡成功
        if (strACSInfo.dwMinor == 1) {
            log.info("刷卡成功");
            //刷脸成功
        } else if (strACSInfo.dwMinor == 75) {
            log.info("刷脸成功");

            long offset = 0;

            System.out.println("strACSInfo.pPicData===="+strACSInfo.pPicData);
            System.out.println("strACSInfo.dwPicDataLen===="+strACSInfo.dwPicDataLen);


            ByteBuffer buffers = strACSInfo.pPicData.getByteBuffer(offset, strACSInfo.dwPicDataLen);
            byte[] bytes = new byte[strACSInfo.dwPicDataLen];
            buffers.rewind();
            buffers.get(bytes);
            BASE64Encoder encoder = new BASE64Encoder();
            String imageBig = encoder.encode(bytes);

            //添加刷脸的回调
            ThDoorControl thDoorControl = thDoorControlService.selectThDoorControlByIp(ip);
            ThFaceRecords thFaceRecords = new ThFaceRecords();
            ThDoorcontrolUser thDoorcontrolUser = thDoorcontrolUserService.selectEmployeeNo(employeeId);
            thFaceRecords.setControlId(thDoorControl.getId());
            thFaceRecords.setEmployeeNo(employeeId);
            thFaceRecords.setCreateTime(new Date());
            thFaceRecords.setStatus("0");//正常开门
            thFaceRecords.setUserType("0");
            if(null == thDoorcontrolUser){
                thFaceRecords.setUserType("1");//员工
            }
            thFaceRecords.setPhoto(imageBig);
            if(userInfo.size()>0 && StringUtils.isNotEmpty(userInfo.get(0))){
                JSONObject jsonObject = userInfo.get(0);
                String name = jsonObject.get("name").toString();
                thFaceRecords.setUserName(name);
            }
            thFaceRecordsService.insertThFaceRecords(thFaceRecords);


            if(thDoorcontrolUser!=null && thDoorControl.getControlPosition().contains("menfang") && thDoorControl.getControlType().equals("out")){
                SysDictData sysDictData = sysDictDataService.selectDictValue("zy_visit","visit_effective_duration");

                Date date = new Date();
                Date beginTime = thDoorcontrolUser.getBeginTime();

                Calendar cal = Calendar.getInstance();
                cal.setTime(beginTime);
                cal.add(Calendar.HOUR,Integer.parseInt(sysDictData.getDictValue()));// 24小时制
                Date control_durationTime = cal.getTime();//门房门禁允许保留的时间

                if(date.compareTo(control_durationTime)>0){
                    //删除用户
                    thDoorcontrolUser.setStatus("1");//删除
                    thDoorcontrolUserService.updateThDoorcontrolUser(thDoorcontrolUser);
                    hkUserService.deleteUserInfo(thDoorControl,employeeId);
                    ThDoorControl thDoorControl_in = thDoorControlService.selectcontrolByPositionAndType("menfang","in");
                    hkUserService.deleteUserInfo(thDoorControl_in,employeeId);
                }
            }

            //刷脸失败
        } else if (strACSInfo.dwMinor == 76) {
            log.info("刷脸失败");
        } else {

        }
    }








}
